package models

import (
	"context"
	"crypto/ecdsa"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/mr-tron/base58"
	"go-chain-api/global"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type WatchAddressConfig struct {
	Id          string `bson:"_id,omitempty" json:"id"`
	ChainId     uint   `bson:"chainId" json:"chainId"`
	ChainName   string `bson:"chainName" json:"chainName"`
	Address     string `bson:"address" json:"address"`
	Token       string `bson:"token" json:"token"`
	CallBackUrl string `bson:"callBackUrl" json:"callBackUrl"`
	UserId      string `bson:"userId" json:"userId"`
	PrivateKey  string `bson:"privateKey" json:"privateKey"`
	Type        string `bson:"type" json:"type"`
	Timestamp   uint64 `bson:"timestamp" json:"timestamp"`
}

// Insert 插入
func (wac WatchAddressConfig) Insert() error {
	client := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	_, err := client.InsertOne(context.TODO(), wac)
	if err != nil {
		return err
	}
	return nil
}

// DeleteById 删除
func (wac WatchAddressConfig) DeleteById(id string) error {
	client := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	objID, err := primitive.ObjectIDFromHex(id)
	if err != nil {
		return err
	}
	deleteResult, err := client.DeleteOne(context.TODO(), bson.M{"_id": objID})
	if err != nil {
		return err
	}
	if deleteResult.DeletedCount == 0 {
		return errors.New("检查ID是否正确")
	}
	return nil
}

// GetList 获取列表
func (wac WatchAddressConfig) GetList(userId string, pageIndex uint, pageSize uint) (int64, []WatchAddressConfig, error) {
	var watchAddressConfigs []WatchAddressConfig
	client := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")

	// 查找
	filter := bson.D{{"userId", userId}}
	clientOptions := options.Find()
	clientOptions.SetSort(bson.D{{"_id", -1}})
	clientOptions.SetSkip(int64(pageIndex))
	clientOptions.SetLimit(int64(pageSize))

	// 获取总数
	count, err := client.CountDocuments(context.TODO(), filter)
	if err != nil {
		return 0, []WatchAddressConfig{}, err
	}

	find, err := client.Find(context.TODO(), filter, clientOptions)
	if err != nil {
		return 0, []WatchAddressConfig{}, err
	}

	err = find.All(context.TODO(), &watchAddressConfigs)
	if err != nil {
		return 0, []WatchAddressConfig{}, err
	}

	return count, watchAddressConfigs, nil
}

func GenerateAddress(userId string, mainCoinType int64, chainName string) (string, error) {
	var watchAddressConfig WatchAddressConfig
	var privateKeyHex string
	var address string
	switch chainName {
	case "TRX":
		privateKey, _ := crypto.GenerateKey()
		privateKeyBytes := crypto.FromECDSA(privateKey)
		publicKey := privateKey.Public()
		publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
		addrStr := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
		addrStr = "41" + addrStr[2:]
		addb, _ := hex.DecodeString(addrStr)
		firstHash := sha256.Sum256(addb)
		secondHash := sha256.Sum256(firstHash[:])
		secret := secondHash[:4]
		addb = append(addb, secret...)
		address = base58.Encode(addb)
		privateKeyHex = hexutil.Encode(privateKeyBytes)[2:]
	default:
		privateKeyRe, err := crypto.GenerateKey()
		if err != nil {
			return "", err
		}
		// 将私钥的D字段（其实是个大数）转换为字节切片
		privateKeyBytes := privateKeyRe.D.Bytes()

		// 将字节切片转换为十六进制字符串
		privateKeyHex = hex.EncodeToString(privateKeyBytes)
		address = crypto.PubkeyToAddress(privateKeyRe.PublicKey).Hex()
	}
	//这个域名到时候得换 这个到时候可以用127.0.0.1:8848
	callBack := global.CallBackUrlConfig.UpgradeUrl
	var userInfo User
	userClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user")
	err := userClient.FindOne(context.TODO(), bson.M{"role": "1"}).Decode(&userInfo)
	if err != nil {
		return "", err
	}

	var chainConfig ChainConfig
	chainConfigClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("scan_config")
	err = chainConfigClient.FindOne(context.TODO(), bson.M{"chainName": chainName, "udunId": mainCoinType}).Decode(&chainConfig)
	if err != nil {
		return "", err
	}

	//这里是存入u盾的address表 所以userId用系统用户的id取创建地址
	watchAddressConfig.UserId = userInfo.Id
	watchAddressConfig.ChainId = chainConfig.ChainID
	watchAddressConfig.PrivateKey = privateKeyHex
	watchAddressConfig.Address = address
	watchAddressConfig.ChainName = chainName
	watchAddressConfig.Type = "udun"
	watchAddressConfig.CallBackUrl = callBack
	err = watchAddressConfig.Insert()
	if err != nil {
		return "", err
	}

	//这里是存入我们自己的address表
	var generateAddressConfig GenerateAddressConfig
	generateAddressConfig.UserId = userId
	generateAddressConfig.ChainId = chainConfig.ChainID
	generateAddressConfig.PrivateKey = privateKeyHex
	generateAddressConfig.Address = address
	generateAddressConfig.ChainName = chainName
	generateAddressConfig.Type = "udun"
	generateAddressConfig.CallBackUrl = callBack
	err = generateAddressConfig.Insert()
	if err != nil {
		return "", err
	}
	return address, nil
}
